use axum::{
    http::StatusCode,
    response::{IntoResponse, Response as AxumResponse},
    Json,
};
use serde::Serialize;

#[cfg(feature = "openapi")]
use utoipa::ToSchema;

/// 统一 API 响应
#[derive(Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct Response<T>
where
    T: Serialize,
{
    /// 状态码: 200-成功, 500-失败
    #[cfg_attr(feature = "openapi", schema(example = 200))]
    pub code: i32,

    /// 提示信息
    #[cfg_attr(feature = "openapi", schema(example = "操作成功"))]
    pub msg: String,

    /// 响应数据
    pub data: Option<T>,

    /// 详细错误信息(包含错误链和堆栈)
    #[serde(skip_serializing_if = "Option::is_none")]
    #[cfg_attr(
        feature = "openapi",
        schema(example = "错误详情: 数据库连接失败\n堆栈信息: ...")
    )]
    pub detail: Option<String>,
}

impl<T> Response<T>
where
    T: Serialize,
{
    /// 成功响应
    pub fn success(data: T) -> Self {
        Self {
            code: 200,
            msg: "ok".to_string(),
            data: Some(data),
            detail: None,
        }
    }

    /// 失败响应
    pub fn failed(msg: impl Into<String>) -> Self {
        Self {
            code: 500,
            msg: msg.into(),
            data: None,
            detail: None,
        }
    }

    /// 失败响应(带详细信息)
    pub fn failed_with_detail(msg: impl Into<String>, detail: impl Into<String>) -> Self {
        Self {
            code: 500,
            msg: msg.into(),
            data: None,
            detail: Some(detail.into()),
        }
    }

    /// 失败响应(带状态码和详细信息)
    pub fn failed_with_code(code: i32, msg: impl Into<String>, detail: Option<String>) -> Self {
        Self {
            code,
            msg: msg.into(),
            data: None,
            detail,
        }
    }
}

// 实现 IntoResponse,让 Response<T> 可以直接作为 handler 返回值
impl<T> IntoResponse for Response<T>
where
    T: Serialize,
{
    fn into_response(self) -> AxumResponse {
        // 所有响应都返回 HTTP 200
        (StatusCode::OK, Json(self)).into_response()
    }
}

pub type AppResult<T> = Result<Response<T>, crate::error::AppError>;
